package designpattern.visitor.ast;

import com.github.javaparser.ast.body.MethodDeclaration;
import com.github.javaparser.ast.body.VariableDeclarator;
import com.github.javaparser.ast.expr.NameExpr;
import com.github.javaparser.ast.visitor.VoidVisitorAdapter;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;

class MethodVariables {
    Set<String> declaredVariables = new HashSet<>();
    Set<String> usedVariables = new HashSet<>();
    String currentMethodName;
    public MethodVariables(String currentMethodName) {
        this.currentMethodName = currentMethodName;
    }
    public void addDeclaredVariable(String var) {
        declaredVariables.add(var);
    }
    public void addUsedVariable(String var) {
        usedVariables.add(var);
    }
    public String getCurrentMethodName() {
        return currentMethodName;
    }
    public Set<String> getUnusedVariables() {
        Set<String> unusedVariables = new HashSet<>();
        for (String var : declaredVariables) {
            if (!usedVariables.contains(var)) {
                unusedVariables.add(var);
            }
        }
        return unusedVariables;
    }
    public void printUnusedVariables() {
        Set<String> unusedVariables = getUnusedVariables();
        for (String var : unusedVariables) {
            System.out.println("警告: 方法 '" + currentMethodName + "' 中的变量 '" + var + "' 已声明但未使用");
        }
    }
}


// 未使用变量检测访问者（使用栈结构传递状态, 每个方法一个状态）
public class UnusedVariableVisitor extends VoidVisitorAdapter<Stack<MethodVariables>> {
    
    @Override
    public void visit(MethodDeclaration md, Stack<MethodVariables> stack) {
        // 创建新的变量状态集合并压入栈
        MethodVariables state = new MethodVariables(md.getNameAsString());
        stack.push(state);
        // 访问方法体
        super.visit(md, stack);
        // 访问完成后，从栈顶获取状态集合并打印
        stack.pop().printUnusedVariables();;
        
    }
    
    @Override
    public void visit(VariableDeclarator vd, Stack<MethodVariables> stack) {
        // 从栈顶获取声明的变量集合
        MethodVariables methodState = stack.peek();
        // 记录声明的变量
        methodState.addDeclaredVariable(vd.getNameAsString());
        super.visit(vd, stack);
    }
    
    @Override
    public void visit(NameExpr ne, Stack<MethodVariables> stack) {
        // 从栈顶获取使用的变量集合
        MethodVariables methodState = stack.peek();
        
        // 记录使用的变量
        methodState.addUsedVariable(ne.getNameAsString());
        super.visit(ne, stack);
    }
}